# -*- coding: utf-8 -*-
#coding=utf-8
# lib for the app 
# const, function, class

import os,time, re
import shutil


#########################
# settings from ./config.ini
#########################
def init_config():
    if not os.path.exists('config.ini'):
        if os.path.exists('config-example.ini'):
            shutil.copyfile('config-example.ini', 'config.ini')
            print("--> 已从config-example.ini创建config.ini")
        else:
            print("--> 错误：config-example.ini不存在")
    else:
        print("--> config.ini已存在")
#
init_config() #如果 config.ini 不存在，就复制一份


# 读取配置文件
import configparser
def getConf(section, item, file_path="config.ini", isBool=False):
	cf = configparser.ConfigParser()
	cf.read(file_path)
	if isBool:
		return cf.getboolean(section, item)
	return cf.get(section, item)


# get env, root_path,
import sys
env=sys.platform #"win32"测试环境;  "linux"生产环境
if env=='linux':
    root_path = getConf("root_path", "linux")
elif env=='win32':
    root_path = getConf("root_path", "windows")

port = getConf("port", "linux") if env=="linux" else getConf("port", "windows")
version=getConf("system", "version", file_path="config-example.ini") #仅 version 从示例配置文件读取
user=getConf("system", "user") #获取登录用户名
passwd=getConf("system", "passwd") #获取登录密码
year=time.strftime("%Y", time.localtime())

# 音频播放器地址
playerPath=getConf("system", "player")

# 从ini中读取不能web删除的文件和文件夹
can_not_delete_on_web_dirs = getConf("system", "can_not_delete_on_web").split(",")

# 是否允许上传文件
allow_file_upload = getConf("system", "allow_file_upload", isBool=True)

# 允许计算文件夹大小
dirs_calc_size = getConf("system", "dirs_calc_size").split(",")


#########################
# web pages
#########################

head='''
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>webPan.py - Mini网盘
%s
    </title>
    <link rel="shortcut icon" href="/static/images/favicon.ico">
    <link rel="stylesheet" href="/static/css/webPan.css" />
    
    <!-- 外链图标 
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
    -->
    <link rel="stylesheet" href="/static/css/font-awesome.min.css">
    
</head>

<body>
<div class="wrap">
    <h1>
        <img src="/static/images/webpan_simple.png" style="height:40px; padding:0 10px;">
        webPan.py
        <span class=version>%s</span>
        <span class=version>
            |
            <a href="/logout">logout</a>
        </span>
    </h1>
</div>


<div class="wrap">
    <fieldset>
        <legend>Upload File</legend>
        <form action="/upload" method="post" enctype="multipart/form-data" id="oBtnForm">
            <input type="file" name="file" id="file" draggable="true" class="fileBox" />
            <input type="hidden" name="uploadDir" value="." />
            <input type="submit" id="submit" value="上传(Upload)" /> 
            <span style='margin-left:30px;'>注意: 本网盘只是临时中转，请及时备份！超过一周的文件可能随时会被<b style='color:red;'>删除</b>！</span>
        </form>
    </fieldset>
</div>

'''
head=head % (version, version);


# for login page
foot0='<div class="wrap footer"> \
    <p>&copy;2020-%s webPan.py %s \
| <a class="fork" target="_blank" href="https://github.com/BioMooc/webPan.py">Fork Me</a> | root_path: '+root_path+'</p> \
allow_file_upload: %s\
<br> \
can_not_delete_on_web: %s\
<br> \
dirs_calc_size: %s\
<br> \
<br>chrome://flags/#block -Secure private network requests | Disabled, Relaunch \
<br>edge://flags/#block-insecure-private-network-requests | Disabled, Relaunch \
</div>'
foot0=foot0 % (year, version, allow_file_upload, ", ".join(can_not_delete_on_web_dirs), ", ".join(dirs_calc_size) );

# for list page
foot=foot0+'</body> \
    <script src="/static/js/main.js"></script> \
    <script src="/static/js/drag_upload.js"></script> \
</html>'





img={
    "file":'<img src="" width="16" height="16" alt="PDF">',
    
    "pdf":'<img src="" border="0" width="16" height="16" alt="PDF">',
    
    "png": '<img src="" border="0" width="16" height="16">',

    
    "html": '<img src="" border="0" width="16" height="16">',

    
    "audio": '<img src="/static/images/icon_mp3.png" border="0" width="16" height="16">',
    "mp4": '<img src="/static/images/icon_mp4.png" border="0" width="16" height="16">',
    
    "note": '<img src="/static/images/notebook.ico" border="0" width="16" height="16">',
    "code": '<img src="/static/images/icon_code.png" border="0" width="16" height="16">',
    "R": '<img src="/static/images/icon_R.png" border="0" width="16" height="16">',
    "py": '<img src="/static/images/icon_py.png" border="0" width="16" height="16">',
    "php": '<img src="/static/images/icon_php.png" border="0" width="16" height="16">',
    "rar": '<img src="/static/images/icon_rar.png" border="0" width="16" height="16">',
    
    "txt": '<img src="/static/images/icon_txt.png" border="0" width="16" height="16">',
    "js": '<img src="/static/images/icon_js.png" border="0" width="16" height="16">', #js
    "bat": '<img src="/static/images/icon_bat.png" border="0" width="16" height="16">', # bat
    "conf": '<img src="/static/images/icon_conf.png" border="0" width="16" height="16">', #css, yaml, yml, conf
    
    "doc": '<img src="/static/images/icon_docx.png" border="0" width="16" height="16">',
    "ppt": '<img src="/static/images/icon_pptx.png" border="0" width="16" height="16">',
    "xls": '<img src="/static/images/icon_xlsx.png" border="0" width="16" height="16">',

    
    "dir": '<img src="">',
    
    'back': '<img src="">',
    
    'order':'<img title="order" class=order src="" style="width:11px;height:9px;">'
    
};


# 字节bytes转化 B\K\M\G\T
#v0.2 保留2位
#v0.3 和 linux 一致
def formatSize(bytes):
    try:
        bytes = float(bytes)
        K = bytes / 1024
    except:
        print("传入的字节格式不对")
        return "Error"
    if K >= 1024:
        M = K / 1024
        if M >= 1024:
            G = M / 1024
            if G>=1024:
                T = G / 1024
                return "%.2fT" % (T)  
            return "%.2fG" % (G)
        else:
            return "%.2fM" % (M)
    else:
        if K<1:
            return "%.0fB" % (bytes)
        return "%.2fK" % (K)


# 获取文件大小
def getDocSize(path):
    try:
        size = os.path.getsize(path)
        return formatSize(size)
    except Exception as err:
        print(err)


# 获取文件夹大小，递归法，返回的是bytes，需要在最终返回值做k/m/g换算
# by: Lin Yanling v0.1 2019.9.4
# v0.2 改为os.path.join
# v0.3 忽略 .git 文件夹
# v0.4 遇到软链接，大小直接记为0
# v0.5 分成2个函数，一个判断是否在list中，一个计算dir大小
# * 有些深文件夹算大小特别慢，打开需要等十秒
# * 修改为指定 dirs_calc_size 下的文件夹才计算dir大小，默认文件夹学习linux直接显示为4k
def dirSize(path, ignoreGit=True):
    # 如果在指定list中，计算该dir大小
    for dir_calc_size in dirs_calc_size:
        dir_calc_size_abs = os.path.abspath( os.path.join(root_path, dir_calc_size) ) #真实路径 
        if is_folder_contained(path, dir_calc_size_abs): #dir1 包含 dir2吗?
            return calcDirSize(path, ignoreGit)
    # 如果不在指定list中，则dir大小直接返回4k
    return 4*1024

# 递归计算dir大小
def calcDirSize(path, ignoreGit=True):
    if ignoreGit==True:
        # 检查路径是否是 .git 目录
        if os.path.isdir(path) and os.path.basename(path) == '.git':
            print("dirSize Ignore .git: ", path)
            return 0

    content = os.listdir(path)
    size = 0
    for v in content:
        if os.path.islink( os.path.join(path, v) ):
            # if is soft link, ignore
            size += 0
        elif os.lstat( os.path.join(path, v) ).st_mode == 4480:
            # if is hard link, ignore
            size += 0
        #if os.path.isfile('/'.join([path,v])):
        elif os.path.isfile( os.path.join(path, v) ):
            size += os.path.getsize(os.path.join(path, v)); #'/'.join([path,v])
        else:
            size += calcDirSize(os.path.join(path, v), ignoreGit) #'/'.join([path,v])
    return size
#



#获取修改时间
# v0.2 考虑 指向不存在地址的软连接
def getModifiedTime(full_path):
    if os.path.islink( full_path ):
        mtime = os.lstat( full_path ).st_mtime
    else:
        mtime = os.stat(full_path).st_mtime;
    file_modify_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(mtime));
    return [file_modify_time, mtime];

# 按正则表达式，去掉某个部分
def strip(str1, reg):
    return re.sub(reg, "", str1)



# check if dir1 lies in dir2?
import os
import sys
def is_folder_contained(inner_dir, outer_dir, debug=False):
    dir1 = os.path.abspath(inner_dir) # long, and detailed
    dir2 = os.path.abspath(outer_dir) # short

    # 检查dir2是否存在
    if not os.path.exists(dir2):
        return False

    # 获取dir1的绝对路径，并且将其分割成一个列表
    dir1_parts = dir1.split(os.path.sep)

    # 从dir1开始遍历，逐级向上比较
    for i in range(len(dir1_parts), 0, -1):
        candidate = os.path.join(*dir1_parts[:i])
        if "linux"==sys.platform:
            candidate=os.path.join("/", candidate)
        
        if debug:
            print(i, dir2, "candidate=", candidate)
        if os.path.exists(candidate) and os.path.isdir(candidate):
            if os.path.samefile(dir2, candidate):
                return True

    return False
#
#is_folder_contained("/home/wangjl/data/web/docs/code/zhangzm/", "/home/wangjl/data/web/docs/code/") #T
#is_folder_contained("/home/wangjl/data/web/docs/code/zhangzm", "/home/wangjl/data/web/docs/code/zhangzm", False) #T
#is_folder_contained("/home/wangjl/data/web/docs/code/", "/home/wangjl/data/web/docs/code/zhangzm") #F

# 清理url，替换 /./ 为 /
def clean_url(url):
    return url.replace('/./', '/')
